home *** CD-ROM | disk | FTP | other *** search
Java Source | 1996-05-21 | 12.0 KB | 456 lines |
- /*
- * @(#)/SliceStack.java 1.4 96/03/31 by Andrew Barclay abb@nuccard.eushc.org
- *
- * Copyright (c) 1995 Andrew B. Barclay All Rights Reserved.
- */
-
- // I like to know what I'm importing for sanity checks.
- import java.applet.Applet ;
- import java.applet.AppletContext ;
- import java.awt.Color ;
- import java.awt.Dimension ;
- import java.awt.Event ;
- import java.awt.Graphics ;
- import java.awt.Image ;
- import java.awt.image.ImageObserver ;
- import java.awt.Rectangle ;
- import java.util.Enumeration ;
-
- import SlicerControl ;
- import SlicerDisplay ;
- import SlicerDisplayInfo ;
- import SlicerDisplayGraphic ;
-
- /**
- * An applet that displays stacks (one on top of another)
- * of orthogonal slices from volume images. It receives the
- * slice data and positioning info from a Volume that is owned
- * by a SlicerControl applet on the same page. Communication with
- * the SlicerControl is through methods of the SlicerDisplay
- * interface. If no SlicerControl appears, the applet will wait
- * indefinitely.
- *
- * @see SlicerDisplay
- * @see SlicerControl
- * @see Volume
- *
- * @version 1.4 96/03/31
- * @author Andrew Barclay
- */
-
- public class SliceStack extends Applet implements ImageObserver, SlicerDisplay {
- // init parameters:
- String controlname ;
- int axis ;
- double thickness ;
- double zoom ;
-
- // state info:
- Thread me ;
- SlicerControl control ;
- SlicerDisplayInfo sdi ;
- Image curimage ;
- int imgw = -1, imgzw = -1 ;
- int imgh = -1, imgzh = -1 ;
- double xscale = 1.0 ;
- double yscale = 1.0 ;
- boolean selected = false ;
- Rectangle hashrects[] = new Rectangle[4] ;
- Color hashcolors[] = new Color[4] ;
- Color bordercolor = null ;
-
- // look and feel:
- static final long updateRate = 100 ;
- static final int xpad = 3 ;
- static final int ypad = 3 ;
- static final int hashheight = 8 ;
- static final int highlightwidth = 3 ;
-
- boolean debug = false ;
-
- public String getAppletInfo() {
- return "SliceStack by Andrew Barclay" ;
- }
-
- public String[][] getParameterInfo() {
- String[][] info = {
- {"control", "string", "name of SlicerControl applet"},
- {"axis", "0|1|2", "X, Y, or Z axis slicing"},
- {"slicethickness", "double", "mm"},
- {"zoom", "double", "zoom factor"},
- } ;
- return info ;
- }
-
- public void init() {
- // clear all the sizes.
- imgw = imgzw = imgh = imgzh = -1 ;
-
- // bug: this has got to go
- String param = getParameter( "AXIS" ) ;
- axis = Integer.parseInt( param ) ;
- dbg( "init - axis="+axis ) ;
-
- param = getParameter( "SLICETHICKNESS" ) ;
- // bug: should check > 0.0 ?
- thickness = (param == null) ? 0.0 : parseDouble( param ) ;
- dbg( "init - thickness="+thickness ) ;
-
- param = getParameter( "ZOOM" ) ;
- zoom = (param == null) ? 1.0 : parseDouble( param ) ;
- dbg( "init - zoom="+zoom ) ;
-
- controlname = getParameter( "CONTROL" ) ;
- dbg( "init - controlname="+controlname ) ;
-
- // handy to see extent of applet:
- //setBackground( Color.black ) ;
- }
-
- // why is there no parseDouble??
- private double parseDouble( String s ) {
- return (Double.valueOf(s)).doubleValue() ;
- }
-
- // Once the runnable is alive, start looking for a control.
- public void start() {
- // Find the named control on this page.
- getControl() ;
-
- // register this with the control.
- sdi = control.register( this, axis, thickness ) ;
- // bug: need to check for null sdi here, throw exception
-
- // initialize our state
- if( thickness == 0.0 ) {
- thickness = sdi.vsize[2] ;
- }
-
- // make slice display isotropic
- double minsize =
- (sdi.vsize[0] < sdi.vsize[1]) ? sdi.vsize[0] : sdi.vsize[1] ;
- xscale = zoom * sdi.vsize[0]/minsize ;
- yscale = zoom * sdi.vsize[1]/minsize ;
-
- setImage( control.getSlice( this, sdi.position ) ) ;
- }
-
- private synchronized void getControl() {
- // sit here and wait for the control to appear.
- while( (control = (SlicerControl)getApplet(controlname)) == null ) {
- try {
- showStatus( "SliceStack"+axis+" waiting for "+controlname+" to appear..." ) ;
- wait(1000);
- } catch (InterruptedException ex) { }
- }
- }
-
- // I get a NullPointerException every time from
- // netscape.applet.MozillaAppletContext.getApplet(String).
- // getApplets() works, so I'll roll my own
- private Applet getApplet( String name ) {
- AppletContext ac = getAppletContext() ;
- Enumeration en = ac.getApplets() ;
- while( en.hasMoreElements() ) {
- Applet ap = (Applet)en.nextElement() ;
- //dbg( "applet="+ap ) ;
- if( (ap instanceof SlicerControl)
- && name.equals(ap.getParameter("NAME")) ) {
- dbg( "getApplet: found a SlicerControl named "+name+"!" ) ;
- return ap ;
- }
- }
- //dbg( "getApplets() done." ) ;
- return null ;
- }
-
- // For the SlicerDisplay interface.
- public void stopInYourTracks() {
- // I want to remove my image consumer, or stop the
- // image load thread???
- destroy() ;
- }
-
- // This isn't being called??
- public Dimension preferredSize() {
- dbg( "preferredSize(), zw="+imgzw+", zh="+imgzh ) ;
- if( imgzw < 0 || imgzh < 0 ) {
- return null ;
- } else {
- return new Dimension( imgzw+xpad*2, imgzh+ypad*2 ) ;
- }
- }
-
- // @return currently displayed image.
- public synchronized void setImage(Image img) {
- curimage = img ;
- // By using updateRate here, we give the display a chance to
- // catch up with rapid changes.
- repaint(updateRate) ;
- showPosition() ;
- }
-
- // @return true if we know image size, else false.
- private synchronized boolean checkSize() {
- if( curimage == null ) {
- return false ;
- }
-
- if (imgzw < 0 || imgzh < 0 ) {
- // This should be only place that we check/set these.
- imgw = curimage.getWidth(this) ;
- imgh = curimage.getHeight(this) ;
- if (imgw < 0 || imgh < 0 ) {
- return false ;
- } else {
- imgzw = (int)( 0.5 + xscale * imgw ) ;
- imgzh = (int)( 0.5 + yscale * imgh ) ;
- // doesn't work on anything but Solaris??
- /*
- resize( imgzw+2*xpad, imgzh+2*ypad ) ;
- layout() ;
- */
- }
- }
- return true ;
- }
-
- void paintHashmarks( Graphics gr ) {
- for( int i = 0 ; i < 4 ; i++ ) {
- if( hashcolors[i] != null ) {
- gr.setColor( hashcolors[i] ) ;
- gr.fillRect( hashrects[i].x, hashrects[i].y,
- hashrects[i].width, hashrects[i].height ) ;
- }
- }
- }
-
- // For the SlicerDisplay interface.
- public void updateHashmarks( SlicerDisplayGraphic sdg ) {
- boolean dopaint = false ;
- bordercolor = sdg.bordercolor ;
-
- if (imgzw < 0 || imgzh < 0 ) {
- return ;
- }
-
- if( sdg.xhashcolor != null ) {
- int xpos = xpad + (int)(0.5+sdg.xhashpos*imgzw) ;
- int ypos ;
- int width = (int)(0.5+sdg.xhashwidth*imgzw) ;
- int height = (int)(0.5+sdg.xhashlength*imgzh) ;
-
- ypos = ypad ;
- // If the shape changes, make a new rectangle...
- if( hashrects[0] == null
- || width != hashrects[0].width
- || height != hashrects[0].height ) {
- hashrects[0] = new Rectangle( xpos, ypos, width, height ) ;
- dopaint = true ;
- // otherwise, just move the old one.
- } else if( xpos != hashrects[0].x || ypos != hashrects[0].y ) {
- hashrects[0].move( xpos, ypos ) ;
- dopaint = true ;
- }
- hashcolors[0] = sdg.xhashcolor ;
-
- ypos = ypad + imgzh - height ;
- // If the shape changes, make a new rectangle...
- if( hashrects[1] == null
- || width != hashrects[1].width
- || height != hashrects[1].height ) {
- hashrects[1] = new Rectangle( xpos, ypos, width, height ) ;
- dopaint = true ;
- // otherwise, just move the old one.
- } else if( xpos != hashrects[1].x || ypos != hashrects[1].y ) {
- hashrects[1].move( xpos, ypos ) ;
- dopaint = true ;
- }
- hashcolors[1] = sdg.xhashcolor ;
- }
-
- if( sdg.yhashcolor != null ) {
- int xpos ;
- int ypos = ypad + (int)(0.5+sdg.yhashpos*imgzh) ;
- int width = (int)(0.5+sdg.yhashlength*imgzw) ;
- int height = (int)(0.5+sdg.yhashwidth*imgzh) ;
-
- xpos = xpad ;
- // If the shape changes, make a new rectangle...
- if( hashrects[2] == null
- || width != hashrects[2].width
- || height != hashrects[2].height ) {
- hashrects[2] = new Rectangle( xpos, ypos, width, height ) ;
- dopaint = true ;
- // otherwise, just move the old one.
- } else if( xpos != hashrects[2].x || ypos != hashrects[2].y ) {
- hashrects[2].move( xpos, ypos ) ;
- dopaint = true ;
- }
- hashcolors[2] = sdg.yhashcolor ;
-
- xpos = xpad + imgzw - width ;
- // If the shape changes, make a new rectangle...
- if( hashrects[3] == null
- || width != hashrects[3].width
- || height != hashrects[3].height ) {
- hashrects[3] = new Rectangle( xpos, ypos, width, height ) ;
- dopaint = true ;
- // otherwise, just move the old one.
- } else if( xpos != hashrects[3].x || ypos != hashrects[3].y ) {
- hashrects[3].move( xpos, ypos ) ;
- dopaint = true ;
- }
- hashcolors[3] = sdg.yhashcolor ;
- }
-
- if( dopaint ) {
- /*
- * This should not use repaint. I need to make a method
- * to set cliprects and do updates in there
- * (damage/repair like IV).
- *
- * By using updateRate here, we give the display a chance
- * to catch up with rapid changes.
- */
- repaint(updateRate) ;
- } else {
- // Don't need a full repaint (e.g. color change).
- paintHashmarks( getGraphics() ) ;
- paintBorder( getGraphics() ) ;
- }
- }
-
- void paintBorder() {
- paintBorder( getGraphics() ) ;
- }
-
- void paintBorder( Graphics gr ) {
- gr.setColor( bordercolor ) ;
- for( int xy = 1 ; xy <= highlightwidth ; xy++ ) {
- gr.drawRect( xy, xy,
- imgzw+2*xpad-2*xy,imgzh+2*ypad-2*xy ) ;
- }
- }
-
- public void paint( Graphics g ) {
- // Must have imgzw and imgzh set before drawing anything.
- if( checkSize() ) {
- // Draw the current image.
- if( xscale == 1.0 && yscale == 1.0 ) {
- g.drawImage( curimage, xpad, ypad, this ) ;
- } else {
- g.drawImage( curimage, xpad, ypad, imgzw, imgzh, this ) ;
- }
-
- paintHashmarks( g ) ;
- paintBorder( g ) ;
- }
- }
-
- public synchronized boolean imageUpdate( Image img, int infoflags,
- int x, int y, int w, int h) {
- if ( curimage == null || img != curimage ) {
- return false ;
- }
-
- boolean ret = true;
- boolean dopaint = false;
- long updatetime = 0;
- if ((infoflags & WIDTH) != 0) {
- dopaint = true ;
- dbg( "SliceStack"+axis+": Got width = " + w ) ;
- }
- if ((infoflags & HEIGHT) != 0) {
- dopaint = true ;
- dbg( "SliceStack"+axis+": Got height = " + h ) ;
- }
- if ((infoflags & (FRAMEBITS | ALLBITS)) != 0) {
- dopaint = true;
- ret = false;
- dbg( "SliceStack"+axis+": Finished" ) ;
- } else if ((infoflags & SOMEBITS) != 0) {
- dopaint = true;
- updatetime = updateRate;
- //dbg( "Got some bits, x=" + x + " y=" + y ) ;
- dbg( "SliceStack"+axis+": Loading..." ) ;
- }
- if ((infoflags & ERROR) != 0) {
- perror( "SliceStack"+axis+": Image load error" ) ;
- ret = false;
- }
-
- if (dopaint) {
- repaint(updatetime);
- }
- return ret;
- }
-
- // Handler for slice selection.
- public boolean keyDown( Event evt, int key ) {
- //dbg( "slice display keyDown" ) ;
- if( control == null || sdi == null || !selected ) {
- return false ;
- }
-
- switch( key ) {
- case Event.UP:
- case 'k':
- case ' ':
- setImage( control.getSlice( this, sdi.position-sdi.vsize[2] ) ) ;
- return true ;
- case Event.DOWN:
- case 'j':
- // BackSpace?
- case 8:
- setImage( control.getSlice( this, sdi.position+sdi.vsize[2] ) ) ;
- return true ;
- default:
- perror( "key press="+key ) ;
- return false ;
- }
- }
-
- public boolean mouseEnter( Event evt, int x, int y ) {
- //dbg( "slice display mouseEnter" ) ;
- requestFocus() ;
- synchronized( this ) {
- selected = true ;
- }
- if( control == null ) {
- return false ;
- } else {
- control.setSelected( this ) ;
- showPosition() ;
- return true ;
- }
- }
-
- public boolean mouseExit( Event evt, int x, int y ) {
- //dbg( "slice display mouseExit" ) ;
- nextFocus() ;
- synchronized( this ) {
- selected = false ;
- }
- return true ;
- }
-
- void showPosition() {
- if( sdi != null ) {
- showStatus( "SliceStack"+sdi.axis+" at "+sdi.position+" mm" ) ;
- }
- }
-
- void dbg( String s ) {
- if( debug ) {
- System.out.println( s ) ;
- showStatus( s ) ;
- }
- }
-
- void perror( String s ) {
- System.err.println( s ) ;
- showStatus( s ) ;
- }
- }
-